/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "driver/gpio/hc32f4a0_gpio.h"
#include "core/include/hc32f4a0_regs_base.h"
#include "core/include/hc32f4a0_regs_gpio.h"
#include "common/hc32f4a0_common.h"
#include "common/hc32f4a0_errno.h"

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief GPIO寄存器写许可
 */
void gpio_unlock(void) {
    WRITE_REG16(HC32F4A0_GPIO->PWPR, 0xA501);
}

/**
 * \brief GPIO寄存器写禁止
 */
void gpio_lock(void) {
    WRITE_REG16(HC32F4A0_GPIO->PWPR, 0xA500);
}

/**
 * \brief GPIO 设置读等待周期
 */
int gpio_read_wait_cycle_set(uint16_t read_wait){

    if ((!IS_GPIO_UNLOCKED()) || (!IS_GPIO_READ_WAIT(read_wait))) {
        return -EINVAL;
    }

    MODIFY_REG16(HC32F4A0_GPIO->PCCR, GPIO_PCCR_RDWT, read_wait);

    return 0;
}

/**
 * \brief GPIO 功能设置
 *
 * \param[in] port GPIO 端口
 * \param[in] pin  GPIO 引脚
 * \param[in] func 要设置的功能
 * \param[in] bfe  是否使能副功能
 *
 * \retval 成功返回 0
 */
int gpio_func_set(uint8_t  port,
                  uint16_t pin,
                  uint8_t  func,
                  uint16_t bfe){
    int                   i;
    volatile uint16_t    *p_pfsrx     = NULL;
    hc32f4a0_gpio_regs_t *p_gpio_regs = NULL;

    if ((port > GPIO_PORT_I) || ((pin & GPIO_PIN_MASK) == 0)) {
        return -EINVAL;
    }
    if (((func > GPIO_FUNC_20) && (func < GPIO_FUNC_32)) || (func > GPIO_FUNC_63)) {
        return -EINVAL;
    }
    if ((bfe != GPIO_PIN_SUBFUN_DISABLE) && (bfe != GPIO_PIN_SUBFUN_ENABLE)) {
        return -EINVAL;
    }
    /* GPIO寄存器写保护中*/
    if (IS_GPIO_UNLOCKED() == FALSE) {
        return -EPERM;
    }

    p_gpio_regs = (hc32f4a0_gpio_regs_t *)HC32F4A0_GPIO_BASE;

    for (i = 0; i < 16; i++) {
        if ((pin & (uint16_t)(1 << i)) != 0) {
            p_pfsrx = (volatile uint16_t *)((uint32_t)(&p_gpio_regs->PFSRA0) +
                    (uint32_t)(port * 0x40) + i * 4);
            WRITE_REG16(*p_pfsrx, (bfe | (uint16_t)func));
        }
    }

    return 0;
}

/**
 * \brief GPIO 配置结构体初始化
 *
 * \param[in] p_gpio_cfg 配置结构体
 */
void gpio_struct_init(struct hc32f4a0_gpio_cfg *p_gpio_cfg){
    if (p_gpio_cfg == NULL) {
        return;
    }

    p_gpio_cfg->pin_sta   = PIN_STATE_RESET;
    p_gpio_cfg->pin_dir   = PIN_DIR_IN;
    p_gpio_cfg->pin_otype = PIN_OTYPE_CMOS;
    p_gpio_cfg->pin_drv   = PIN_DRV_LOW;
    p_gpio_cfg->latch     = PIN_LATCH_OFF;
    p_gpio_cfg->pull_up   = PIN_PU_OFF;
    p_gpio_cfg->invert    = PIN_INVERT_OFF;
    p_gpio_cfg->pin_itype = PIN_ITYPE_SMT;
    p_gpio_cfg->ex_int    = PIN_EXINT_OFF;
    p_gpio_cfg->pin_attr  = PIN_ATTR_DIGITAL;
}

/**
 * \brief GPIO 配置
 *
 * \param[in] port       要初始化的端口
 * \param[in] pin        要初始化的引脚
 * \param[in] p_gpio_cfg 要配置的参数
 *
 * \retval 成功返回0
 */
int gpio_cfg(uint8_t                   port,
             uint16_t                  pin,
             struct hc32f4a0_gpio_cfg *p_gpio_cfg){
    volatile uint16_t *p_pcrx;
    uint16_t           pin_pos;
    uint16_t           pcr_val;
    int                ret = 0;

    if (p_gpio_cfg == NULL) {
        return -EINVAL;
    }

    for (pin_pos = 0; pin_pos < 16; pin_pos++) {
        if ((pin & (1 << pin_pos)) != 0) {
            p_pcrx = (volatile uint16_t *)((uint32_t)(&HC32F4A0_GPIO->PCRA0) +
                    ((uint32_t)(port) * 0x40) + pin_pos * 4);

            pcr_val = p_gpio_cfg->ex_int | p_gpio_cfg->pin_itype | p_gpio_cfg->invert |
                    p_gpio_cfg->pull_up | p_gpio_cfg->latch | p_gpio_cfg->pin_drv | p_gpio_cfg->pin_otype |
                    p_gpio_cfg->pin_sta | p_gpio_cfg->pin_dir | p_gpio_cfg->pin_attr;
            WRITE_REG16(*p_pcrx, pcr_val);
        }
    }

    return ret;
}

/**
 * \brief GPIO 反初始化
 */
void gpio_deinit(uint8_t port, uint16_t pin){
    struct hc32f4a0_gpio_cfg cfg;

    if (!IS_GPIO_UNLOCKED()) {
        return;
    }

    gpio_struct_init(&cfg);

    gpio_cfg(port, pin, &cfg);
    /* 复位寄存器值*/
    WRITE_REG16(HC32F4A0_GPIO->PSPCR, GPIO_PSPCR_RESET_VALUE);
    WRITE_REG16(HC32F4A0_GPIO->PCCR, GPIO_PCCR_RESET_VALUE);
    WRITE_REG16(HC32F4A0_GPIO->PINAER, GPIO_PINAER_RESET_VALUE);
}

/**
 * \brief 设置 GPIO 引脚的状态
 */
int gpio_sta_get(uint8_t port, uint16_t pin, uint8_t *p_sta){
    volatile uint16_t *p_pidrx;

    if (p_sta == NULL) {
        return -EINVAL;
    }

    p_pidrx = (volatile uint16_t *)((uint32_t)(&HC32F4A0_GPIO->PIDRA) + 0x10 * port);

    if ((READ_REG16(*p_pidrx) & (pin)) != 0) {
        *p_sta = 1;
    } else {
        *p_sta = 0;
    }

    return 0;
}

/**
 * \brief 设置 GPIO 引脚的状态
 */
int gpio_sta_set(uint8_t port, uint16_t pin, uint8_t sta){
    volatile uint16_t *p_pidrx;
    volatile uint16_t *p_porrx;

    if (((sta != 1) && (sta != 0))) {
        return -EINVAL;
    }

    if (sta == 1) {
        p_pidrx = (volatile uint16_t *)((uint32_t)(&HC32F4A0_GPIO->POSRA) + 0x10 * port);
        SET_REG16_BIT(*p_pidrx, pin);
    } else {
        p_porrx = (volatile uint16_t *)((uint32_t)(&HC32F4A0_GPIO->PORRA) + 0x10 * port);
        SET_REG16_BIT(*p_porrx, pin);
    }

    return 0;
}

/**
 * \brief GPIO 引脚的状态翻转
 */
int gpio_sta_toggle(uint8_t port, uint16_t pin){
    volatile uint16_t *p_port_x;

    if ((port > GPIO_PORT_I) || ((pin & GPIO_PIN_MASK) == 0)) {
        return -EINVAL;
    }

    p_port_x = (volatile uint16_t *)((uint32_t)(&HC32F4A0_GPIO->POTRA) + 0x10UL * port);
    SET_REG16_BIT(*p_port_x, pin);

    return 0;
}













